﻿#region Copyright and License Notice
// Copyright (C)2010-2016 - Rob Levine and other contributors
// http://configgen.codeplex.com
// 
// This file is part of ConfigGen.
// 
// ConfigGen is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// ConfigGen is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License and 
// the GNU Lesser General Public License along with ConfigGen.  
// If not, see <http://www.gnu.org/licenses/>
#endregion

using System.IO;
using System.Xml;
using ConfigGen.Core.TemplateLoader;
using NUnit.Framework;

namespace ConfigGen.Core.Tests.TemplateLoader
{
    [TestFixture]
    public class TemplatePreferencesLoaderTests
    {
        [Test]
        public void PrettyPrintPreferencesLoadCorrectly()
        {
            const string xml =
                @"<?xml version=""1.0""?>
<configuration xmlns:cg=""http://roblevine.co.uk/Namespaces/ConfigGen/1/0/"">
    <cg:TemplatePreferences>
        <cg:PrettyPrint enabled=""true"" lineLength=""123""/>
    </cg:TemplatePreferences>
    <appSettings>
        <add key=""MySetting"" value=""MyValue""/>
    </appSettings>
</configuration>";

            using (var sourceTemplateStream = new MemoryStream())
            using (var writer = new StreamWriter(sourceTemplateStream))
            using (var targetTemplateStream = new MemoryStream())
            {
                writer.Write(xml);
                writer.Flush();
                sourceTemplateStream.Position = 0;

                var itemUnderTest = new TemplatePreferencesLoader();
                var preferences = itemUnderTest.LoadPreferences(sourceTemplateStream, targetTemplateStream);
                Assert.IsNotNull(preferences, "preferences: should not be null");
               
                Assert.IsNotNull(preferences.PrettyPrint, "PrettyPrint: should not be null");
                Assert.IsTrue(preferences.PrettyPrint.Enabled, "PrettyPrint.Enabled: incorrect");
                Assert.AreEqual(123, preferences.PrettyPrint.LineLength, "PrettyPrint.LineLength: incorrect");
            }
        }

        [Test]
        public void TokenPreferencesLoadCorrectly()
        {
            const string xml =
                @"<?xml version=""1.0""?>
<configuration xmlns:cg=""http://roblevine.co.uk/Namespaces/ConfigGen/1/0/"">
    <cg:TemplatePreferences>
        <cg:Token startDelimiter=""{%"" endDelimiter=""%}"" />
    </cg:TemplatePreferences>
    <appSettings>
        <add key=""MySetting"" value=""MyValue""/>
    </appSettings>
</configuration>";

            using (var sourceTemplateStream = new MemoryStream())
            using (var writer = new StreamWriter(sourceTemplateStream))
            using (var targetTemplateStream = new MemoryStream())
            {
                writer.Write(xml);
                writer.Flush();
                sourceTemplateStream.Position = 0;

                var itemUnderTest = new TemplatePreferencesLoader();
                var preferences = itemUnderTest.LoadPreferences(sourceTemplateStream, targetTemplateStream);
                Assert.IsNotNull(preferences, "preferences: should not be null");

                Assert.IsNotNull(preferences.Token, "Token: should not be null");
                Assert.AreEqual("{%", preferences.Token.StartDelimiter, "Token.StartDelimiter: incorrect");
                Assert.AreEqual("%}", preferences.Token.EndDelimiter, "Token.EndDelimiter: incorrect");
            }
        }

        [Test]
        public void OutputProcessingPreferencesLoadCorrectly()
        {
            const string xml =
                @"<?xml version=""1.0""?>
<configuration xmlns:cg=""http://roblevine.co.uk/Namespaces/ConfigGen/1/0/"">
    <cg:TemplatePreferences>
        <cg:OutputProcessing removeRootElement=""true""/>
    </cg:TemplatePreferences>
    <appSettings>
        <add key=""MySetting"" value=""MyValue""/>
    </appSettings>
</configuration>";

            using (var sourceTemplateStream = new MemoryStream())
            using (var writer = new StreamWriter(sourceTemplateStream))
            using (var targetTemplateStream = new MemoryStream())
            {
                writer.Write(xml);
                writer.Flush();
                sourceTemplateStream.Position = 0;

                var itemUnderTest = new TemplatePreferencesLoader();
                var preferences = itemUnderTest.LoadPreferences(sourceTemplateStream, targetTemplateStream);
                Assert.IsNotNull(preferences, "preferences: should not be null");

                Assert.IsNotNull(preferences.OutputProcessing, "OutputProcessing: should not be null");
                Assert.IsTrue(preferences.OutputProcessing.RemoveRootElement, "OutputProcessing.RemoveRootElement: incorrect");
            }
        }

        [Test]
        public void FunctionsCorrectlyIfRootNodeIsNotConfiguration()
        {
            const string xml =
                @"<?xml version=""1.0""?>
<rootNode xmlns:cg=""http://roblevine.co.uk/Namespaces/ConfigGen/1/0/"">
    <cg:TemplatePreferences>
        <cg:PrettyPrint enabled=""true"" lineLength=""123""/>
    </cg:TemplatePreferences>
    <appSettings>
        <add key=""MySetting"" value=""MyValue""/>
    </appSettings>
</rootNode>";

            using (var sourceTemplateStream = new MemoryStream())
            using (var writer = new StreamWriter(sourceTemplateStream))
            using (var targetTemplateStream = new MemoryStream())
            {
                writer.Write(xml);
                writer.Flush();
                sourceTemplateStream.Position = 0;

                var itemUnderTest = new TemplatePreferencesLoader();
                var preferences = itemUnderTest.LoadPreferences(sourceTemplateStream, targetTemplateStream);

                Assert.IsNotNull(preferences, "preferences: should not be null");
                Assert.IsNotNull(preferences.PrettyPrint, "PrettyPrint: should not be null");
                Assert.IsTrue(preferences.PrettyPrint.Enabled, "PrettyPrint.Enabled: incorrect");
                Assert.AreEqual(123, preferences.PrettyPrint.LineLength, "PrettyPrint.LineLength: incorrect");
            }
        }

        [Test]
        public void PreferencesSectionRemovedAfterExtraction()
        {
            const string xml =
                @"<?xml version=""1.0""?>
<rootNode xmlns:cg=""http://roblevine.co.uk/Namespaces/ConfigGen/1/0/"">
    <cg:TemplatePreferences>
        <cg:PrettyPrint enabled=""true"" lineLength=""123""/>
    </cg:TemplatePreferences>
    <appSettings>
        <add key=""MySetting"" value=""MyValue""/>
    </appSettings>
</rootNode>";
            using (var sourceTemplateStream = new MemoryStream())
            using (var writer = new StreamWriter(sourceTemplateStream))
            using (var targetTemplateStream = new MemoryStream())
            {
                writer.Write(xml);
                writer.Flush();
                sourceTemplateStream.Position = 0;

                var itemUnderTest = new TemplatePreferencesLoader();
                itemUnderTest.LoadPreferences(sourceTemplateStream, targetTemplateStream);
                targetTemplateStream.Position = 0;

                var xmlDocument = new XmlDocument();
                var xmlNamespaceManager = new XmlNamespaceManager(xmlDocument.NameTable);
                xmlNamespaceManager.AddNamespace("cg", "http://roblevine.co.uk/Namespaces/ConfigGen/1/0/");
                xmlDocument.Load(targetTemplateStream);
                Assert.IsNull(xmlDocument.SelectSingleNode("/rootNode/cg:TemplatePreferences", xmlNamespaceManager), "TemplatePreferences not removed");  
            }
        }


        [Test]
        public void PreferencesSectionMissingReturnsDefaults()
        {
            const string xml =
                @"<?xml version=""1.0""?>
<configuration xmlns:cg=""http://roblevine.co.uk/Namespaces/ConfigGen/1/0/"">
    <appSettings>
        <add key=""MySetting"" value=""MyValue""/>
    </appSettings>
</configuration>";

            using (var sourceTemplateStream = new MemoryStream())
            using (var writer = new StreamWriter(sourceTemplateStream))
            using (var targetTemplateStream = new MemoryStream())
            {
                writer.Write(xml);
                writer.Flush();
                sourceTemplateStream.Position = 0;

                var itemUnderTest = new TemplatePreferencesLoader();
                var preferences = itemUnderTest.LoadPreferences(sourceTemplateStream, targetTemplateStream);
              
                Assert.IsNotNull(preferences, "Preferences: should not be null");
                Assert.IsNotNull(preferences.PrettyPrint, "PrettyPrint: should not be null");
                Assert.IsNotNull(preferences.Token, "Token: should not be null");
                var defaults = new TemplatePreferences();
                Assert.AreEqual(defaults.PrettyPrint.Enabled, preferences.PrettyPrint.Enabled, "PrettyPrint.Enabled: incorrect");
                Assert.AreEqual(defaults.PrettyPrint.LineLength, preferences.PrettyPrint.LineLength, "PrettyPrint.LineLength: incorrect");
                Assert.AreEqual(defaults.Token.StartDelimiter, preferences.Token.StartDelimiter, "Token.StartDelimiter: incorrect");
                Assert.AreEqual(defaults.Token.EndDelimiter, preferences.Token.EndDelimiter, "Token.EndDelimiter: incorrect");
                Assert.AreEqual(defaults.OutputProcessing.RemoveRootElement, preferences.OutputProcessing.RemoveRootElement, "OutputProcessing.RemoveRootElement: incorrect");
            }
        }

        [Test]
        public void NonOverriddenPreferencesReturnDefaults()
        {
            const string xml =
                @"<?xml version=""1.0""?>
<configuration xmlns:cg=""http://roblevine.co.uk/Namespaces/ConfigGen/1/0/"">
    <cg:TemplatePreferences>
        <cg:PrettyPrint enabled=""true""/>
        <cg:Token startDelimiter=""{%""/>
    </cg:TemplatePreferences>
    <appSettings>
        <add key=""MySetting"" value=""MyValue""/>
    </appSettings>
</configuration>";

            using (var sourceTemplateStream = new MemoryStream())
            using (var writer = new StreamWriter(sourceTemplateStream))
            using (var targetTemplateStream = new MemoryStream())
            {
                writer.Write(xml);
                writer.Flush();
                sourceTemplateStream.Position = 0;

                var itemUnderTest = new TemplatePreferencesLoader();
                var preferences = itemUnderTest.LoadPreferences(sourceTemplateStream, targetTemplateStream);

                Assert.IsNotNull(preferences, "Preferences: should not be null");
                Assert.IsNotNull(preferences.PrettyPrint, "PrettyPrint: should not be null");
                Assert.IsNotNull(preferences.Token, "Token: should not be null");
                var defaults = new TemplatePreferences();
                Assert.AreEqual(true, preferences.PrettyPrint.Enabled, "PrettyPrint.Enabled: incorrect");
                Assert.AreEqual(defaults.PrettyPrint.LineLength, preferences.PrettyPrint.LineLength, "PrettyPrint.LineLength: incorrect");
                Assert.AreEqual("{%", preferences.Token.StartDelimiter, "Token.StartDelimiter: incorrect");
                Assert.AreEqual(defaults.Token.EndDelimiter, preferences.Token.EndDelimiter, "Token.EndDelimiter: incorrect");
            }
        }

        [Test]
        public void MultipleTemplatePreferencesSectionsThrows()
        {
            const string xml =
                @"<?xml version=""1.0""?>
<configuration xmlns:cg=""http://roblevine.co.uk/Namespaces/ConfigGen/1/0/"">
  <cg:TemplatePreferences>
        <cg:PrettyPrint enabled=""true"" lineLength=""123""/>
    </cg:TemplatePreferences>
  <cg:TemplatePreferences>
        <cg:PrettyPrint enabled=""true"" lineLength=""123""/>
    </cg:TemplatePreferences>
    <appSettings>
        <add key=""MySetting"" value=""MyValue""/>
    </appSettings>
</configuration>";

            using (var sourceTemplateStream = new MemoryStream())
            using (var writer = new StreamWriter(sourceTemplateStream))
            using (var targetTemplateStream = new MemoryStream())
            {
                writer.Write(xml);
                writer.Flush();
                sourceTemplateStream.Position = 0;

                var itemUnderTest = new TemplatePreferencesLoader();
                Assert.Throws<TemplateLoadException> (() => itemUnderTest.LoadPreferences(sourceTemplateStream, targetTemplateStream));
            }
        }
    }
}
